package net.ex337.hotrepart.loadtester.executors;

import java.util.List;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import net.ex337.hotrepart.loadtester.telemetry.GeneratedLoad;
import net.ex337.hotrepart.loadtester.telemetry.LoadGenerator;
import net.ex337.hotrepart.loadtester.telemetry.LoadRecorder;
import net.ex337.hotrepart.loadtester.telemetry.LoadRecorderDelegate;

/**
 *
 * A schedule-based load runner that records the load generated by the
 * items it runs. This load is then tallied at a regular interval.
 *
 * @author ian
 */
public final class LoadGeneratingScheduledExecutor extends ScheduledThreadPoolExecutor implements LoadRecorder {

	private LoadRecorder loadRecorderDelegate;
	private int delay;
	private int period;
	private TimeUnit periodUnits;

    /**
     *
     * @param type The "type" of load, so far one of "reads", "writes" or "updates".
     */
	public LoadGeneratingScheduledExecutor(String type, int threads, int delay, int period, TimeUnit periodUnits) {
		super(threads);
		this.delay = delay;
		this.period = period;
		this.periodUnits = periodUnits;
		
		this.loadRecorderDelegate = new LoadRecorderDelegate(type);
	}

    /**
     * @param load The load to schedule. Generally only called once.
     */
    public void addLoadGenerator(LoadGenerator load) {
        //not needed - done in decorateTask
        //load.setLoadReceiver(this);
		super.scheduleAtFixedRate(load, delay, period, periodUnits);
	}

    /*
     * Where the decoration takes place. Could be moved above...
     */
	@Override
	protected <V> RunnableScheduledFuture<V> decorateTask(Runnable r, RunnableScheduledFuture<V> rsv) {
		((LoadGenerator)r).setLoadReceiver(this);
		return super.decorateTask(r, rsv);
	}

	@Override
	protected void afterExecute(Runnable r, Throwable t) {
		if(t != null) {
			addThrowable(t);
		}
		super.afterExecute(r, t);
	}

    /*
     * Delegate methods below here.
     */

	public void addThrowable(Throwable t) {
		loadRecorderDelegate.addThrowable(t);
	}
    public void addThrowables(List<Throwable> e) {
        loadRecorderDelegate.addThrowables(e);
    }

	public void addGeneratedLoad(GeneratedLoad load) {
		loadRecorderDelegate.addGeneratedLoad(load);
	}

	public GeneratedLoad getGeneratedLoadToDate() {
		return loadRecorderDelegate.getGeneratedLoadToDate();
	}

	public List<Throwable> getThrowablesToDate() {
		return loadRecorderDelegate.getThrowablesToDate();
	}


}

